package it.koutifaris.travianmap.dal.sqlservices.revision;

import static it.koutifaris.testforclassutils.IsTestForAssert.assertIsTestFor;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import it.koutifaris.travianmap.dal.RevisionService.Revision;
import it.koutifaris.travianmap.dal.sqlservices.AbstractMapDbTest;
import it.koutifaris.travianmap.dal.sqlservices.MapSqlContract.Revisions;

import java.util.Date;
import java.util.List;

import junit.framework.Assert;
import android.content.ContentValues;

public class SqlRevisionServiceTest extends AbstractMapDbTest {

	private SqlRevisionService service;

	@Override
	protected void overridableSetUp() {
		service = new SqlRevisionService(getDbHelper().getReadableDatabase());
	}

	public void testPkgAndName() {
		assertIsTestFor(SqlRevisionService.class);
	}

	public void testRevisionExistOnEmptyTable() {
		Revision revision = mock(Revision.class);
		when(revision.getId()).thenReturn(1L);
		when(revision.getDay()).thenReturn(new Date());

		boolean revisionFound = service.revisionExist(revision);

		Assert.assertFalse(revisionFound);
	}

	public void testGetLatestRevisionOnEmptyTable() {
		Revision latestRevision = service.getLatestRevision();
		Assert.assertEquals(NullRevision.nullRevision(), latestRevision);
	}

	public void testFindRevisionForDayOnEmptyTable() {
		Revision revision = service.findRevisionForDay(new Date());
		Assert.assertNull(revision);
	}

	public void testListAllRevisionOnEmptyTable() {
		List<Revision> revisions = service.listAllRevisions();
		Assert.assertTrue(revisions.isEmpty());
	}

	public void testListRevisionsOnEmptyTable() {
		List<Revision> revisions = service.listRevisions(new Date(), new Date());
		Assert.assertTrue(revisions.isEmpty());
	}

	public void testSameRevisionForSameDay() {
		Date date = new Date(304273800000L);
		Date datePlusSomeTime = new Date(date.getTime() + 1000 * 3600);

		Assert.assertTrue(service.newRevisionForDay(date).equals(service.newRevisionForDay(datePlusSomeTime)));
	}

	public void testRevisionExist() {
		Revision revision = createAndInsertRevisionForDay(new Date(304273800000L));

		boolean revisionFound = service.revisionExist(revision);

		Assert.assertTrue(revisionFound);
	}

	public void testGetRevision() {
		Revision expectedRevision = createAndInsertRevisionForDay(new Date(304273800000L));

		Revision revision = service.findRevisionForDay(expectedRevision.getDay());

		Assert.assertEquals(expectedRevision, revision);
	}

	public void testGetLatestRevision() {
		Revision revisionA = createAndInsertRevisionForDay(new Date(304273800000L));
		Revision revisionB = createAndInsertRevisionForDay(addOneDay(revisionA.getDay()));

		Revision revision = service.getLatestRevision();

		Assert.assertEquals(revisionB, revision);
	}

	public void testListAllRevisions() {
		Date testDate = new Date(304273800000L);
		Revision revisionA = createAndInsertRevisionForDay(testDate);
		Revision revisionB = createAndInsertRevisionForDay(addOneDay(testDate));

		List<Revision> revisions = service.listAllRevisions();

		Assert.assertEquals(2, revisions.size());
		Assert.assertEquals(revisionB, revisions.get(0));
		Assert.assertEquals(revisionA, revisions.get(1));
	}

	public void testListRevisions() {
		Revision revisionA = createAndInsertRevisionForDay(new Date(304273800000L));
		Revision revisionB = createAndInsertRevisionForDay(addOneDay(revisionA.getDay()));
		Revision revisionC = createAndInsertRevisionForDay(addOneDay(revisionB.getDay()));

		List<Revision> revisions = service.listRevisions(revisionB.getDay(), revisionC.getDay());

		Assert.assertEquals(2, revisions.size());
		Assert.assertEquals(revisionC, revisions.get(0));
		Assert.assertEquals(revisionB, revisions.get(1));
	}

	private Revision createAndInsertRevisionForDay(Date date) {
		Revision revision = service.newRevisionForDay(date);
		getDbHelper().getWritableDatabase().insertOrThrow(Revisions.TABLE_NAME, null, contentValuesWith(revision));

		return revision;
	}

	private Date addOneDay(Date date) {
		return addNDays(date, 1);
	}

	private Date addNDays(Date date, int numberOfDays) {
		return new Date(date.getTime() + numberOfDays * 24 * 3600 * 1000);
	}

	private ContentValues contentValuesWith(Revision revision) {
		ContentValues contentValues = new ContentValues();
		contentValues.put(Revisions.COLUMN_NAME_REVISION_ID, revision.getId());
		contentValues.put(Revisions.COLUMN_NAME_DATE, revision.getDay().getTime());

		return contentValues;
	}

}
